package com.dna.common.lang;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;

import com.dna.common.io.MultiStreamJack;
import com.dna.common.io.StreamJack;

public class PlugableProcess extends Process {

	private ProcessBuilder processBuilder;
	private Process process;
	
	private MultiStreamJack input;
	private MultiStreamJack output;
	
	private List<InputStream> tempInputs = new ArrayList<InputStream>();
	private List<OutputStream> tempOutputs = new ArrayList<OutputStream>();
	
	public PlugableProcess(List<String> command) {
		processBuilder = new ProcessBuilder(command);
	}
	
	public PlugableProcess(String...command) {
		processBuilder = new ProcessBuilder(command);
	}
	
	public void start() throws IOException {
		process = processBuilder.start();
		InputStream[] initialInputs = new InputStream[0];
		if(tempInputs!=null)
			initialInputs = tempInputs.toArray(new InputStream[tempInputs.size()]);
		OutputStream[] initialOutputs = new OutputStream[0];
		if(tempOutputs!=null)
			initialOutputs = tempOutputs.toArray(new OutputStream[tempOutputs.size()]);
		input = new MultiStreamJack(StreamJack.DEFAULT_BUFFER_SIZE, initialInputs, getOutputStream());
		output = new MultiStreamJack(StreamJack.DEFAULT_BUFFER_SIZE, new InputStream[]{getInputStream()}, initialOutputs);
		input.start();
		output.start();
		input.autoFlush(true);
		output.autoFlush(true);
		for(InputStream in : tempInputs)
			input.addInput(in);
		tempInputs.clear();
		for(OutputStream out : tempOutputs)
			input.addOutput(out);
		tempOutputs.clear();
		
	}
	
	@Override
	public void destroy() {
		if(process != null) {
			process.destroy();
			try {
				input.close();
				output.close();
			} catch (IOException e) {
				System.err.println(e.getLocalizedMessage());
			}
		}
	}

	@Override
	public int exitValue() {
		if(process!=null)
			return process.exitValue();
		return 0;
	}

	@Override
	public InputStream getErrorStream() {
		if(process==null)
			return null;
		return process.getErrorStream();
	}

	@Override
	public InputStream getInputStream() {
		if(process==null)
			return null;
		return process.getInputStream();
	}

	@Override
	public OutputStream getOutputStream() {
		if(process==null)
			return null;
		return process.getOutputStream();
	}

	@Override
	public int waitFor() throws InterruptedException {
		if(process!=null)
			return process.waitFor();
		return 0;
	}

	public boolean addInput(InputStream inputStream) {
		if(input==null)
			return tempInputs.add(inputStream);
		return input.addInput(inputStream);
	}
	
	public boolean addOutput(OutputStream outputStream) {
		if(output==null)
			return tempOutputs.add(outputStream);
		return output.addOutput(outputStream);
	}
}
